package com.zpself.module.JDK8新功能.日期时间新API;

import org.junit.Test;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author By ZengPeng
 * @Description JDK8 之前的时间 API 存在线程安全问题，并且设计混乱。因此，在 JDK8 就重新设计了一套 API。
 * 一.LocalDate，LocalTime，LocalDateTime 它们都是不可变类，用法差不多。以 LocalDate 为例。
 * 二.时间戳 Instant
 * 三.日期段 Duration、 Period 但是 Period 只能精确到年月日。
 * 四.时区 ZoneId
 * 五.线程安全：日期时间格式化  DateTimeFormatter
 * @date in  2021/3/2 13:39
 * @Modified By
 */
public class TestDate {
    @Test
    //线程不安全
    public void test1() throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Future<Date> future = executorService.submit(() -> sdf.parse("20200905"));
            list.add(future);
        }
        Thread.sleep(3000);
        for (Future<Date> future : list) {
            if (future.isDone())
                System.out.println(future.get());
        }
    }

    @Test
    //线程安全
    public void testSafe() throws Exception {
        // SimpleDateFormat 改为 DateTimeFormatter
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // Date 改为 LocalDate
        List<Future<LocalDate>> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            //日期解析改为 LocalDate.parse("20200905",dtf)
            Future<LocalDate> future = executorService.submit(() -> LocalDate.parse("20200905",dtf));
            list.add(future);
        }
        for (Future<LocalDate> future : list) {
            System.out.println(future.get());
        }
    }




    @Test
    //--------------------------------二、时间戳 Instant------------------------------
    public void testInstant() {
        //Instant 代表的是到从 UTC 时区 1970年1月1日0时0分0秒开始计算的时间戳。
        Instant now = Instant.now();
        System.out.println(now.toString()); // 2020-09-05T14:11:07.074Z
        System.out.println(now.toEpochMilli()); // 毫秒数， 1599315067074
    }

    @Test
    //--------------------------------三、时间段 Duration 、Period------------------------------
    public void testDuration() {
        //用于表示时间段 ，可以表示 LocalDateTime 和 Instant 之间的时间段，用 between 创建。
        LocalDateTime today1 = LocalDateTime.now(); //今天的日期时间
        LocalDateTime tomorrow = today1.plusDays(1); //明天
        Duration duration = Duration.between(today1, tomorrow); //第二个参数减去第一个参数的时间差
        System.out.println(duration.toDays()); //总天数，1
        System.out.println(duration.toHours()); //小时，24
        System.out.println(duration.toMinutes()); //分钟，1440
        System.out.println(duration.getSeconds()); //秒，86400
        System.out.println(duration.toMillis()); //毫秒，86400000
        System.out.println(duration.toNanos()); // 纳秒，86400000000000


        LocalDate today = LocalDate.now(); //今天
        LocalDate date = LocalDate.of(2021, 10, 1); //国庆节
        //1. 用 between 创建 Period 对象
        Period period = Period.between(today, date);
        System.out.println(period); // P26D
        //2. 用 of 创建 Period 对象
        Period of = Period.of(2020, 9, 6);
        System.out.println(of); // P2020Y9M6D
        // 距离国庆节还有 0 年 0 月 26 天
        System.out.printf("距离国庆节还有 %d 年 %d 月 %d 天", period.getYears(), period.getMonths(), period.getDays());
    }


    @Test
    //--------------------------------四、时区 ZoneId------------------------------
    //ZoneId 表示不同的时区。
    public void testZoneId() {
        //getAvailableZoneIds() ，获取所有时区信息，大概40多个时区
        //of(id)，根据时区id获得对应的 ZoneId 对象
        //systemDefault，获取当前时区
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        availableZoneIds.forEach(System.out::println); //打印所有时区
        ZoneId of = ZoneId.of("Asia/Shanghai");   //获取亚洲上海的时区对象
        System.out.println(of);
        System.out.println(ZoneId.systemDefault()); //当前时区为： Asia/Shanghai
    }


    @Test
    //--------------------------------五、日期时间格式化 DateTimeFormatter------------------------------
    //JDK1.8 提供了线程安全的日期格式化类 DateTimeFormatter。
    public void testDateTimeFormatter() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 1. 日期时间转化为字符串。有两种方式
        String format = dtf.format(LocalDateTime.now());
        System.out.println(format); // 2020-09-05 23:02:02
        String format1 = LocalDateTime.now().format(dtf); //实际上调用的也是 DateTimeFormatter 类的format方法
        System.out.println(format1); // 2020-09-05 23:02:02

        // 2. 字符串转化为日期。有两种方式，需要注意，月和日位数要补全两位
        //第一种方式用的是，DateTimeFormatter.ISO_LOCAL_DATE_TIME ，格式如下
        LocalDateTime parse = LocalDateTime.parse("2020-09-05T00:00:00");
        System.out.println(parse); // 2020-09-05T00:00
        //第二种方式可以自定义格式
        LocalDateTime parse1 = LocalDateTime.parse("2020-09-05 00:00:00", dtf);
        System.out.println(parse1); // 2020-09-05T00:00
    }
}
